// BombManCore.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "BombManCore.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

// This is an example of an exported variable
BOMBMANCORE_API int nBombManCore=0;

// This is an example of an exported function.
BOMBMANCORE_API int fnBombManCore(void)
{
	return 42;
}

// This is the constructor of a class that has been exported.
// see BombManCore.h for the class definition
CBombManCore::CBombManCore()
{
	return;
}

#define ASSERT(a) \
	if(!(a)) \
		printf("assert failed|%s|%s|%d\n",__FILE__,__FUNCTION__,__LINE__);

#define FIRE_LIFE_TIME 8
#define BOMB_LIFE_TIME 200
#define DEFAULT_BOMB_POWER 20
#define DEFAULT_PROTECT_TIME 40

static int temp_map_width = 40;
static int temp_map_height = 40;
int temp_map[] = {
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,
	0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,1,1,1,1,1,0,
	0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,
	0,0,0,0,0,0,1,2,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,2,1,0,1,1,0,0,1,1,1,1,1,1,1,
	0,0,1,1,0,0,2,1,0,1,1,0,0,1,1,1,1,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,
	0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,
	0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,1,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,
	0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,1,1,1,1,1,1,1,
	0,0,0,0,0,0,2,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,1,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
};

//         2 wall , 1 block , 0 null 
//w through  no        no      yes
//can fire   no        yes     yes
//f through  no        no      yes


Map::Tiled::Tiled()
{
	m_fire = false;
	m_put_bomb = -1;
	m_bomb_life = BOMB_LIFE_TIME;
	m_fire_life = 0;
	m_bomb_power = 1;
}

bool Map::Tiled::can_walk_through()
{
	return m_p == 0;
}

bool Map::Tiled::can_fire()
{
	return m_p <= 1;
}

//for starting show fire
//for change the tiled
void Map::Tiled::fire()
{
	m_fire = true;
	m_put_bomb = -1;
	m_p = 0;
	m_fire_life = FIRE_LIFE_TIME;
	m_bomb_life = 0;
}
//for stoping show fire
void Map::Tiled::fire_off()
{
	m_fire = false;
	m_fire_life = 0;
}

bool Map::Tiled::is_fire()
{
	return m_fire;
}
//for checking whether fire this bomb
bool Map::Tiled::is_put_bomb()
{
	return m_put_bomb != -1;
}

int Map::Tiled::get_bomb_puter()
{
	return m_put_bomb;
}
//for checking whether fire this bomb
void Map::Tiled::put_bomb(int _man_index,long _bomb_power)
{
	//ASSERT(m_fire == false);
	ASSERT(can_walk_through());
	ASSERT(can_walk_through());
	m_put_bomb = _man_index;
	m_bomb_power = _bomb_power;
	m_bomb_life = BOMB_LIFE_TIME;
}

long Map::Tiled::get_bomb_life()
{
	return m_bomb_life;
}

long Map::Tiled::get_fire_life()
{
	return m_fire_life;
}

void  Map::Tiled::ui_update()
{
	if(m_fire_life > 0) m_fire_life--;
	if(m_bomb_life > 0) m_bomb_life--;
}
//////////////////////////////////////////////
bool Map::resize(int w, int h)
{
	clear();

	m_tiled = new Tiled*[w];
	if(m_tiled == NULL)
		return false;
	for(int i=0;i<w;i++)
	{
		m_tiled[i] = new Tiled[h];
		if(m_tiled[i] == NULL)
		{
			for(int e=i;e>=0;e--)
				delete m_tiled[e];
			return false;
		}
	}
	m_w = w;
	m_h = h;
	return true;
}


Map::Map()
{
	m_w = m_h = 0;
	m_tiled = NULL;
}
Map::~Map()
{
	clear();
}

void Map::clear()
{
	if(m_tiled)
	{
		for(int i=0;i<m_w;i++)
		{
			delete m_tiled[i];
		}
		delete m_tiled;
		m_tiled = NULL;
		m_w = m_h = 0;
	}
	m_born_position.clear();

	std::vector<Creature*>::iterator iter = m_creatrues.begin();
	for(;iter!= m_creatrues.end();iter++)
	{
		delete *iter;
	}
	m_creatrues.clear();
}

void Map::load()
{
	resize(temp_map_width,temp_map_height);
	for(int w=0;w<m_w;w++)
		for(int h=0;h<m_h;h++)
			m_tiled[w][h].m_p = temp_map[h*temp_map_width + w];
	

	m_born_position.push_back(Position(0,0));
	m_born_position.push_back(Position(temp_map_width-1,temp_map_height-1));


	Creature *_c = new Creature(0,this);
	m_creatrues.push_back(_c);
	Creature *_c1 = new Creature(1,this);
	m_creatrues.push_back(_c1);
}

Creature * Map::get_creature(int _index)
{
	if(m_creatrues.size() <= _index)
		return NULL;
	else
		return m_creatrues[_index];
}
/*
* set bomb only set a sprite to show Animate
*/
void Map::Explode(int x, int y)
{
	typedef struct _Pos
	{
		int x;
		int y;
		_Pos(int _x,int _y)
		{
			x = _x;
			y = _y;
		}
	}_Pos;
	std::list<_Pos> _bombs;
	ASSERT(m_tiled[x][y].can_walk_through());
	m_tiled[x][y].fire();
	int _power = m_tiled[x][y].get_bomb_power();
	for(int i=x+1,p=1;i<m_w;i++,p++)
	{
		if(m_tiled[i][y].can_fire() && p<=_power)
		{
			if(m_tiled[i][y].is_put_bomb())
				_bombs.push_back(_Pos(i,y));
			if(m_tiled[i][y].can_walk_through())
			{
				m_tiled[i][y].fire();
				continue;
			}
			else
			{
				m_tiled[i][y].fire();
				break;
			}
		}
		else
			break;
	}
	//
	for(int i=x-1,p=1;i>=0;i--,p++)
	{
		if(m_tiled[i][y].can_fire() && p<=_power)
		{
			if(m_tiled[i][y].is_put_bomb())
				_bombs.push_back(_Pos(i,y));
			if(m_tiled[i][y].can_walk_through())
			{
				m_tiled[i][y].fire();
				continue;
			}
			else
			{
				m_tiled[i][y].fire();
				break;
			}
		}
		else
			break;
	}
	//
	for(int i=y+1,p=1;i<m_h;i++,p++)
	{
		if(m_tiled[x][i].can_fire() && p<=_power)
		{
			if(m_tiled[x][i].is_put_bomb())
				_bombs.push_back(_Pos(x,i));
			if(m_tiled[x][i].can_walk_through())
			{
				m_tiled[x][i].fire();
				continue;
			}
			else
			{
				m_tiled[x][i].fire();
				break;
			}
		}
		else
			break;
	}
	//
	for(int i=y-1,p=1;i>=0;i--,p++)
	{
		if(m_tiled[x][i].can_fire() && p<=_power)
		{
			if(m_tiled[x][i].is_put_bomb())
				_bombs.push_back(_Pos(x,i));
			if(m_tiled[x][i].can_walk_through())
			{
				m_tiled[x][i].fire();
				continue;
			}
			else
			{
				m_tiled[x][i].fire();
				break;
			}
		}
		else
			break;
	}
	std::list<_Pos>::iterator iter = _bombs.begin();
	for(;iter!=_bombs.end();iter++)
	{
		Explode(iter->x,iter->y);
	}
}
void Map::set_bomb(int x,int y,int _man_index,long _bomb_power)
{
	m_tiled[x][y].put_bomb(_man_index,_bomb_power);
}

int Map::get_plays_count()
{
	return m_born_position.size();
}
Position Map::get_play_born_position(int _index)
{
	if(_index >= m_born_position.size())
		return Position(0,0);
	return m_born_position[_index];
}

void Map::ui_update()
{
	for(int w=0;w<get_width();w++)
	{
		for(int h=0;h<get_height();h++)
		{
			m_tiled[w][h].ui_update();

			if(m_tiled[w][h].is_put_bomb() && m_tiled[w][h].get_bomb_life() <= 0)
				Explode(w,h);
			else if(m_tiled[w][h].is_fire() && m_tiled[w][h].get_fire_life() <= 0)
				m_tiled[w][h].fire_off();
		}
	}

	std::vector<Creature*>::iterator iter = m_creatrues.begin();
	for(;iter!= m_creatrues.end();iter++)
	{
		if(m_tiled[(*iter)->get_x()][(*iter)->get_y()].is_fire() && !(*iter)->is_protectd())
			on_die((*iter)->get_index());
		(*iter)->ui_update();
	}
}

void Map::on_die(int _index)
{
	m_creatrues[_index]->on_die();
}

/////////////////////////////////////////
Creature::Creature(int _index, Map *_m)
	:Radar(_m,_m->get_play_born_position(_index))
{
	m_index = _index;
	m_m = _m;
	on_born();
	m_bomb_power = DEFAULT_BOMB_POWER;
	dead_count = 0;
}

Creature::~Creature()
{
	m_m = NULL;
}

void Creature::on_born()
{
	m_protect_time = DEFAULT_PROTECT_TIME;
	Position _p = m_m->get_play_born_position(m_index);
	this->set_position(_p);
}

void Creature::on_die()
{
	dead_count++;
	on_born();
}

bool Creature::move_left()
{
	if(is_left_side())
		return false;
	if(m_m->get_tiled(this->my_left())->can_walk_through())
	{
		Position::move_left();
		return true;
	}
	return false;
}
bool Creature::move_right()
{
	if(is_right_side(m_m->m_w))
		return false;
	if(m_m->get_tiled(this->my_right())->can_walk_through())
	{
		Position::move_right();
		return true;
	}
	return false;
}
bool Creature::move_up()
{
	if(is_up_side())
		return false;
	if(m_m->get_tiled(this->my_up())->can_walk_through())
	{
		Position::move_up();
		return true;
	}
	return false;
}
bool Creature::move_down()
{
	if(is_down_side(m_m->m_h))
		return false;
	if(m_m->get_tiled(this->my_down())->can_walk_through())
	{
		Position::move_down();
		return true;
	}
	return false;
}
void Creature::set_bomb()
{
	m_m->set_bomb(get_x(),get_y(),m_index,m_bomb_power);
}

void Creature::explode()
{
	for(int w=0;w<m_m->get_width();w++)
		for(int h=0;h<m_m->get_height();h++)
		{
			if(m_m->get_tiled(w,h)->is_put_bomb() && m_m->get_tiled(w,h)->get_bomb_puter() == m_index)
				m_m->Explode(w,h);
		}
}

void Creature::ui_update()
{
	if(m_protect_time > 0)
		m_protect_time--;
}


Radar::Radar(Map* _m,Position &_p)
	:Position(_p)
{
	m_m = _m;
}
////////////////////////////////////////////////////
Radar::Detected Radar::detect_up()
{
	Detected d;

	int _map_width = m_m->get_width();
	int _map_height = m_m->get_height();

	int _man_x = get_x();
	int _man_y = get_y();
	d.obj =  Detected_Wall;

	if(this->is_up_side())
	{
		d.distance = 1;
	}
	else
	{
		Position p = get_position();
		do
		{
			p.move_up();
			if(m_m->get_tiled(p)->is_fire())
			{
				d.obj = Detected_Fire;
				break;
			}
			if(m_m->get_tiled(p)->is_put_bomb())
			{
				d.obj =  Detected_Bomb;
				break;
			}
			if(m_m->get_tiled(p)->can_walk_through() == false)
			{
				if(m_m->get_tiled(p)->can_fire())
				{
					d.obj =  Detected_brick;		
					break;
				}
				else
				{
					d.obj =  Detected_Wall;		
					break;
				}
			}
		}while(!p.is_up_side());

		d.distance = _man_y - p.get_y();
	}
	return d;
}
Radar::Detected Radar::detect_down()
{
	Detected d;

	int _map_width = m_m->get_width();
	int _map_height = m_m->get_height();

	int _man_x = get_x();
	int _man_y = get_y();
	d.obj =  Detected_Wall;

	if(is_down_side(_map_height))
	{
		d.distance = 1;
	}
	else
	{
		Position p = get_position();
		do
		{
			p.move_down();
			if(m_m->get_tiled(p)->is_fire())
			{
				d.obj = Detected_Fire;
				break;
			}
			if(m_m->get_tiled(p)->is_put_bomb())
			{
				d.obj =  Detected_Bomb;
				break;
			}
			if(m_m->get_tiled(p)->can_walk_through() == false)
			{
				if(m_m->get_tiled(p)->can_fire())
				{
					d.obj =  Detected_brick;		
					break;
				}
				else
				{
					d.obj =  Detected_Wall;		
					break;
				}
			}
		}while(!p.is_down_side(_map_height));
		d.distance = p.get_y() - _man_y;
	}
	return d;
}
Radar::Detected Radar::detect_left()
{
	Detected d;

	int _map_width = m_m->get_width();
	int _map_height = m_m->get_height();

	int _man_x = get_x();
	int _man_y = get_y();
	d.obj =  Detected_Wall;

	if(is_left_side())
	{
		d.distance = 1;
	}
	else
	{
		Position p = get_position();
		do
		{
			p.move_left();
			if(m_m->get_tiled(p)->is_fire())
			{
				d.obj = Detected_Fire;
				break;
			}
			if(m_m->get_tiled(p)->is_put_bomb())
			{
				d.obj =  Detected_Bomb;
				break;
			}
			if(m_m->get_tiled(p)->can_walk_through() == false)
			{
				if(m_m->get_tiled(p)->can_fire())
				{
					d.obj =  Detected_brick;		
					break;
				}
				else
				{
					d.obj =  Detected_Wall;		
					break;
				}
			}
		}while(!p.is_left_side());
		d.distance = _man_x - p.get_x();
	}
	return d;
}
Radar::Detected Radar::detect_right()
{
	Detected d;

	int _map_width = m_m->get_width();
	int _map_height = m_m->get_height();

	int _man_x = get_x();
	int _man_y = get_y();
	d.obj =  Detected_Wall;

	if(is_right_side(_map_width))
	{
		d.distance = 1;
	}
	else
	{
		Position p = get_position();
		do
		{
			p.move_right();
			if(m_m->get_tiled(p)->is_fire())
			{
				d.obj = Detected_Fire;
				break;
			}
			if(m_m->get_tiled(p)->is_put_bomb())
			{
				d.obj =  Detected_Bomb;
				break;
			}
			if(m_m->get_tiled(p)->can_walk_through() == false)
			{
				if(m_m->get_tiled(p)->can_fire())
				{
					d.obj =  Detected_brick;		
					break;
				}
				else
				{
					d.obj =  Detected_Wall;		
					break;
				}
			}
		}while(!p.is_right_side(_map_width));
		d.distance = p.get_x() - _man_x;
	}
	return d;
}